package cn.loioi.config;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.shiro.authz.HostUnauthorizedException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.beetl.core.Format;
import org.beetl.core.Function;
import org.beetl.core.TagFactory;
import org.beetl.core.misc.BeetlUtil;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.beetl.ext.spring.BeetlSpringView;
import org.beetl.ext.spring.BeetlSpringViewResolver;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.google.common.collect.Lists;

import cn.loioi.web.components.beetl.format.MessageFormat;
import cn.loioi.web.components.beetl.format.StatusFormat;
import cn.loioi.web.components.beetl.fun.PageUtil;
import cn.loioi.web.components.beetl.tag.TestTag;
import cn.loioi.web.components.spring.converter.CustomDateConverter;
import net.sf.ehcache.CacheManager;

/**
 * Spring MVC 配置
 * @文件 :SpringMvcConfig.java
 * @作者 :cn.loioi
 * @创建时间 :2016年10月13日 下午1:12:09
 */
@Order(0)
@Configuration
@ComponentScan("cn.loioi.web.controller")
@Import(value = { DataSourceConfig.class, ShiroSourceConfig.class })
public class SpringMvcConfig extends WebMvcConfigurationSupport {

	/**
	 * Beetl 视图解析器
	 * @return
	 */
	@Bean
	public BeetlSpringViewResolver beetlSpringViewResolver() {
		// 自定义标签
		Map<String, TagFactory> tagFactorys = new HashMap<>();
		tagFactorys.put("test", new TestTag());
		// 自定义格式化
		Map<String, Format> formats = new HashMap<>();
		formats.put("status", new StatusFormat());
		formats.put("message", new MessageFormat());
		// 自定义函数
		Map<String, Function> functions = new HashMap<>();
		functions.put("PageUtil", new PageUtil());

		// Beetl配置类
		BeetlGroupUtilConfiguration configuration = new BeetlGroupUtilConfiguration();
		configuration.setTagFactorys(tagFactorys);
		configuration.setFormats(formats);
		configuration.setFunctions(functions);
		configuration.setRoot(BeetlUtil.getWebRoot() + "/WEB-INF/beetl/");
		configuration.init();
		// Beetl视图解释器
		BeetlSpringViewResolver viewResolver = new BeetlSpringViewResolver();
		viewResolver.setViewClass(BeetlSpringView.class);
		viewResolver.setConfig(configuration);
		viewResolver.setContentType("text/html;charset=utf-8");
		viewResolver.setSuffix(".html");
		viewResolver.setOrder(2);
		return viewResolver;
	}

	/**
	 * fastJson 消息转换器
	 * @return
	 */
	@Bean
	public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
		FastJsonHttpMessageConverter messageConverter = new FastJsonHttpMessageConverter();
		messageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8));
		return messageConverter;
	}

	/**
	 * 文件上传配置
	 * @return
	 */
	@Bean
	public CommonsMultipartResolver multipartResolver() {
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		multipartResolver.setMaxUploadSize(10 * 1024 * 1024);
		return multipartResolver;
	}

	/**
	 * 异常统一处理
	 * @return
	 */
	@Bean
	public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
		Properties properties = new Properties();
		properties.put(UnauthorizedException.class.getName(), "/error/401");
		properties.put(UnauthenticatedException.class.getName(), "/error/401");
		properties.put(HostUnauthorizedException.class.getName(), "/error/401");
		properties.put(NoHandlerFoundException.class.getName(), "/error/404");

		SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
		resolver.setDefaultErrorView("/error/500");
		resolver.setDefaultStatusCode(500);
		resolver.setExceptionAttribute("ex");
		resolver.setExceptionMappings(properties);
		return resolver;
	}

	/**
	 * 缓存配置
	 * @return
	 */
	@Bean(name = "net.sf.ehcache.CacheManager")
	public CacheManager cacheManager() {
		EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
		ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("spring_cache.xml"));
		ehCacheManagerFactoryBean.afterPropertiesSet();
		return ehCacheManagerFactoryBean.getObject();
	}

	/**
	 * 缓存管理器
	 * @return
	 */
	@Bean(name = "org.springframework.cache.ehcache.EhCacheCacheManager")
	public EhCacheCacheManager ehCacheCacheManager() {
		EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
		ehCacheCacheManager.setCacheManager(cacheManager());
		return ehCacheCacheManager;
	}

	/**
	 * 内容协商器配置。将后缀为json的配置为json处理，后缀为jspx的为页面处理
	 */
	@Override
	protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.defaultContentType(MediaType.TEXT_HTML);
		configurer.mediaType("json", MediaType.APPLICATION_JSON_UTF8);
	}

	/**
	 * 添加视图解析器
	 */
	@Override
	protected void configureViewResolvers(ViewResolverRegistry registry) {
		registry.viewResolver(beetlSpringViewResolver());
		registry.enableContentNegotiation(new FastJsonJsonView());
	}

	/**
	 * 添加消息转换器
	 */
	@Override
	protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(fastJsonHttpMessageConverter());
	}

	/**
	 * 添加异常统一处理
	 */
	@Override
	protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
		exceptionResolvers.add(simpleMappingExceptionResolver());
	}

	/**
	 * 格式转换器
	 */
	@Override
	protected void addFormatters(FormatterRegistry registry) {
		registry.addConverter(new CustomDateConverter());
	}

	/**
	 * 添加静态资源路径
	 */
	@Override
	protected void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
		registry.addResourceHandler("/error/**").addResourceLocations("/error/");
		registry.addResourceHandler("/upload/**").addResourceLocations("/upload/");
		registry.addResourceHandler("/favicon.ico").addResourceLocations("/favicon.ico");
	}

	/**
	 * 跨域配置
	 */
	@Override
	protected void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/api/**").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS");
	}
}